package com.polaris.live.viewmodel.live

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.polaris.live.common.cacha.CacheUtil
import com.polaris.live.common.constant.CommonConst
import com.polaris.live.common.manager.withCountdown
import com.polaris.live.common.manager.withRetry
import com.polaris.live.common.network.HTTP_ERROR_CODE
import com.polaris.live.common.network.HTTP_SUCCESS_CODE
import com.polaris.live.common.network.request
import com.polaris.live.common.network.requestLoading
import com.polaris.live.common.network.state.ResultState
import com.polaris.live.common.network.state.paresException
import com.polaris.live.common.network.state.paresResult
import com.polaris.live.common.util.ToastGravity
import com.polaris.live.constant.LiveConst
import com.polaris.live.im.sfs.COMMAND_CALL_PUBLIC_SCREEN
import com.polaris.live.im.sfs.bean.live.CallPublicScreenMessage
import com.polaris.live.im.sfs.bean.live.CallSignalingMessage
import com.polaris.live.im.sfs.core.SmartFoxQueueManager
import com.polaris.live.manager.AppConfigManager
import com.polaris.live.manager.LiveStateManager
import com.polaris.live.net.gameService
import com.polaris.live.net.liveService
import com.polaris.live.net.payerService
import com.polaris.live.resp.back_resp.CallCheckResp
import com.polaris.live.resp.back_resp.CallConnectResp
import com.polaris.live.resp.back_resp.CallGameReadyResp
import com.polaris.live.resp.back_resp.CallPromotionResp
import com.polaris.live.resp.back_resp.CallStartResp
import com.polaris.live.resp.back_resp.CallVo
import com.polaris.live.resp.back_resp.LiveStartGameResp
import com.polaris.live.resp.back_resp.PartyGameResp
import com.polaris.live.resp.back_resp.StreamSwitchResp
import com.polaris.live.resp.back_resp.WeekStarResp
import com.polaris.live.resp.bean.ZegoGameEventBean
import com.polaris.live.resp.event.BackgroundEvent
import com.polaris.live.resp.go_resp.CallIdBean
import com.polaris.live.resp.go_resp.SwimultaneousBean
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus

/**
 * CallViewModel
 *
 * @author Created by lucas on 2023/11/12 14:59
 * @since 1.0.0
 */
class CallVideoViewModel : LiveViewModel() {

    var isForeground = true //是否时在前台

    var isForegroundClose = true //是否时在前台关闭
    var callInfo: CallVo? = null
    var callBean: CallStartResp? = null
    var callMessage: CallSignalingMessage? = null

    //应答后双方建立连接
    val callConnectLiveData = MutableLiveData<ResultState<CallConnectResp>>()
    fun callConnect(callId: Long) {
        invokeCallConnect(callId, 0)
    }

    private fun invokeCallConnect(callId: Long, retryCount: Int) {
        request({ liveService.callConnect(CallIdBean(callId)) }, {
            callConnectLiveData.paresResult(it)
            //连接成功停止接听超时
            stopAnswerTimeout()
        }, {
            if (retryCount < 1) {
                invokeCallConnect(callId, retryCount + 1)
            } else {
                callConnectLiveData.paresException(it)
            }
        })
    }

    //接听超时
    val answerTimeoutLiveData = MutableLiveData<Unit>()
    private var answerTimeoutJob: Job? = null
    fun launchAnswerTimeout() {
        answerTimeoutJob = viewModelScope.launch {
            try {
                delay(getDelayMillis())
                answerTimeoutLiveData.value = Unit
            } finally {
                if (answerTimeoutJob == coroutineContext[Job]) {
                    answerTimeoutJob = null
                }
            }
        }
    }

    private fun stopAnswerTimeout() {
        answerTimeoutJob?.cancel()
        answerTimeoutJob = null
    }

    private var killJob: Job? = null
    fun killActivityTimeout(time: Long) {
        killJob = viewModelScope.launch {
            try {
                delay(time)
                EventBus.getDefault().post(BackgroundEvent(0))
            } finally {
                if (killJob == coroutineContext[Job]) {
                    killJob = null
                }
            }
        }
    }

    fun stopKillActivityTimeout() {
        killJob?.cancel()
        killJob = null
    }

    private fun getDelayMillis(): Long {
        return AppConfigManager.getConfig(CommonConst.Configs.callNotAnswerTimeout)
            ?.toLongOrNull()
            ?: LiveConst.ANSWER_TIMEOUT
    }

    //发送公屏消息
    fun sendPublicMessage(message: CallPublicScreenMessage) {
        viewModelScope.launch {
            try {
                SmartFoxQueueManager.sendLiveMessage(COMMAND_CALL_PUBLIC_SCREEN, message)
            } catch (t: Throwable) {
                ToastGravity.showGravity(t.message)
            }
        }
    }

    //通话心跳
    val callHeartbeatLiveData = MutableLiveData<ResultState<CallCheckResp>>()
    val callHeartbeatFailureLiveData = MutableLiveData<Boolean>()
    private var callHeartbeatFailureCount = 0
    private var callHeartbeatJob: Job? = null
    fun launchCallHeartbeat(callId: Long, callStartTime: Long) {
        callHeartbeatFailureCount = 0
        callHeartbeatJob = viewModelScope.launch {
            try {
                while (isActive) {
                    callHeartbeatFailureCount = try {
                        val resp = liveService.callCheck(
                            CallIdBean(
                                callId,
                                LiveStateManager.isRecharging()
                            )
                        ).also {
                            callHeartbeatLiveData.paresResult(it)
                        }

                        if (resp.code == HTTP_SUCCESS_CODE) {
                            0
                        } else {
                            if (resp.code == HTTP_ERROR_CODE) {
                                callHeartbeatFailureCount + 1
                            } else {
                                //出现服务器异常，直接停止
                                Int.MAX_VALUE
                            }
                        }
                    } catch (_: Throwable) {
                        callHeartbeatFailureCount + 1
                    }

                    if (callHeartbeatFailureCount >= 3) {
                        callHeartbeatFailureLiveData.value = true
                    }

                    val delayTime = computeHeartbeatDelay(callStartTime)
                    delay(delayTime)
                }
            } finally {
                if (callHeartbeatJob == coroutineContext[Job]) {
                    callHeartbeatJob = null
                }
            }
        }
    }

    //通话页面悬浮价格查询
    val callPayLiveData = MutableLiveData<ResultState<List<CallPromotionResp>>>()
    fun getCallPromotion() {
        request({ payerService.getCallPromotion() }, callPayLiveData)
    }

    private fun computeHeartbeatDelay(callStartTime: Long): Long {
        val serviceTime = CacheUtil.getServerTime()
        val interval = serviceTime - callStartTime
        val finalInterval = if (interval == 0L) {
            LiveConst.HEARTBEAT_TIME
        } else {
            interval
        }
        return LiveConst.HEARTBEAT_TIME - finalInterval % LiveConst.HEARTBEAT_TIME
    }

    //通话计时
    val callCountdownLiveData = MutableLiveData<Long>()
    private var callCountdownJob: Job? = null
    fun launchCallCountdown(callStartTime: Long) {
        callCountdownJob = viewModelScope.launch {
            try {
                withCountdown(Long.MAX_VALUE, 1000L, {
                    callCountdownLiveData.value = CacheUtil.getServerTime() - callStartTime
                })
            } finally {
                if (callCountdownJob == coroutineContext[Job]) {
                    callCountdownJob = null
                }
            }
        }
    }

    //同声传译开关
    fun openSwimultaneous(callId: Long, open: Boolean) {
        requestLoading({ liveService.simultaneoutsOpen(SwimultaneousBean(callId, open)) }, {})
    }

    val isShowRechargeLiveData = MutableLiveData<Boolean>()
    private var isShowJob: Job? = null
    private var lastIsRecharging: Boolean? = null
    fun launchRecharge() {
        isShowJob = viewModelScope.launch {
            try {
                withCountdown(Long.MAX_VALUE, 2000, {
                    val recharging = LiveStateManager.isFastRecharging()
                    if (recharging && lastIsRecharging != true) {
                        isShowRechargeLiveData.value = true
                    }
                    lastIsRecharging = recharging
                })
            } finally {
                if (isShowJob == coroutineContext[Job]) {
                    isShowJob = null
                }
            }
        }
    }

    /**
     * 停止通话的轮询请求
     */
    override fun resetLiveJob() {
        super.resetLiveJob()

        callHeartbeatJob?.cancel()
        callHeartbeatJob = null
        callCountdownJob?.cancel()
        callCountdownJob = null
    }

    override fun onCleared() {
        super.onCleared()
        isShowJob?.cancel()
        isShowJob = null
    }

    /**
     * 上传zego游戏事件
     */
    fun zegoGameEvent(zegoGameEventBean: ZegoGameEventBean) {
        viewModelScope.launch {
            try {
                //这里重试3次，并且第一次不等待
                withRetry(3, initDelay = 0L) {
                    liveService.zegoGameEvent(zegoGameEventBean)
                }
            } catch (_: Throwable) {
            }
            LiveConst.GameType
        }
    }

    /**
     * 获取单个数据
     */
    val getOnePartyGameData = MutableLiveData<ResultState<PartyGameResp>>()
    fun getOnePartyGame(gameId: Int) {
        requestLoading(
            { liveService.getOnePartyGame(gameId) },
            getOnePartyGameData
        )
    }

    /**
     * 开始游戏
     */
    val gameStartData = MutableLiveData<ResultState<Any>>()
    fun gameStart(liveId: Long, @LiveConst.BusinessType businessType: Int) {
        requestLoading(
            { liveService.partyGameStart(LiveStartGameResp(liveId, businessType)) },
            gameStartData
        )
    }

    /**
     * 准备
     */
    val callGameReadyData = MutableLiveData<ResultState<Any>>()
    fun callGameReady(businessId: Long, @LiveConst.BusinessType businessType: Int, ready: Boolean) {
        requestLoading(
            { liveService.callGameReady(CallGameReadyResp(businessId, businessType, ready)) },
            callGameReadyData
        )
    }

    /**
     * 流切换
     */
    val streamSwitchData = MutableLiveData<ResultState<Any>>()
    fun streamSwitch(callId: Long, open: Boolean) {
        requestLoading(
            { liveService.streamSwitch(StreamSwitchResp(callId, open)) },
            streamSwitchData
        )
    }

    /**
     * 周星数据轮询
     */
    private var weeklyStarRankJob: Job? = null

    fun pollingWeeklyStarRank() {
        if (weeklyStarRankJob != null) return
        weeklyStarRankJob = viewModelScope.launch {
            try {
                while (isActive) {
                    getWeeklyStarRank()
                    delay(15000)
                }
            } finally {
                if (weeklyStarRankJob == coroutineContext[Job]) {
                    weeklyStarRankJob = null
                }
            }
        }
    }

    fun cancelPollingWeeklyStarRank() {
        weeklyStarRankJob?.cancel()
        weeklyStarRankJob = null

    }

    //获取周星数据
    val weeklyStarRankData = MutableLiveData<ResultState<WeekStarResp>>()
    fun getWeeklyStarRank() {
        request({ gameService.getWeeklyStarRank() }, weeklyStarRankData)
    }

    //索要禮物
    val inviteGiftData = MutableLiveData<ResultState<Any>>()
    fun inviteGift(callid: Long) {
        request({ liveService.inviteGift(CallIdBean(callid)) }, inviteGiftData)
    }

}